package ec.edu.ups.cidi.siia.plamdep.utils.hilos;

import java.util.ArrayList;
import java.util.List;

import ec.edu.ups.cidi.siia.plamdep.utils.Log;
import ec.edu.ups.cidi.siia.plamdep.utils.Utils;

public abstract class ProcesoGestionado 
{

	protected List<ProcessListener>listeners=new ArrayList<ProcessListener>();
	private long timeout=0;
	private long timeTranscurrido=0;
	private Thread hiloProceso=null;
	private Thread hiloReloj=null;
	private boolean procesIsAlive=true;
	private Runnable reloj=new Runnable() 
	{
		public void run() 
		{
			try 
			{
				while(true)
				{
				Thread.sleep(1000);
				timeTranscurrido++;
				if(timeTranscurrido>=timeout)
				{	
					for(ProcessListener lp:listeners) lp.onTimeout();
					if(procesIsAlive)
						matarProceso();
					else return;
					
					
				}
				}
			} catch (InterruptedException e) {e.printStackTrace();}
		}
	};
	
	private Runnable proceso=new Runnable() 
	{
		
		public void run() {
			for(ProcessListener lp:listeners)	lp.onStart();
			try
			{
				implementacion();
				
			}catch(Exception ex)
			{
				for(ProcessListener lp:listeners)	lp.onError(ex);
			}
			matarProceso();
		}
	};
	
	
	
	
	/**
	 * Mata el hilo del proceso en ejecucion
	 */
	private void matarProceso()
	{		
		procesIsAlive=false;
		for(ProcessListener lp:listeners)	lp.onEnd();
		if(hiloProceso!=null)
			if(hiloProceso.isAlive())
				hiloProceso.stop();
		if(hiloReloj!=null)
			if(hiloReloj.isAlive())
				hiloReloj.stop();
		hiloProceso=null;
		hiloReloj=null;
		Utils.garbageCleaner();
		
	}
	/**
	 * Inicializa el hilo del proceso
	 */
	public void arrancarProceso()
	{
		if(hiloProceso==null)
		{
			hiloProceso=new Thread(proceso);
			hiloProceso.start();
		}
		if(timeout>0)
		{
			if(hiloReloj==null)
			{
				hiloReloj=new Thread(reloj);
				hiloReloj.start();
			}
		}	
	}

	public void addListenner(ProcessListener listener)
	{
		if(listener!=null)
			listeners.add(listener);
	}
	public long getTimeout() {
		return timeout;
	}
	/**
	 * Establece el timeout en segundos
	 * @param timeout
	 */
	public void setTimeout(long timeout) {
		this.timeout = timeout;
	}
	public abstract void implementacion();
	
}
